package misc

import scala.collection.mutable.ArrayBuffer

/**
  * Created by shichen on 2017/6/22.
  * http://www.artima.com/scalazine/articles/stackable_trait_pattern.html
  */

abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}

class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]()

  override def get(): Int = buf.remove(0)

  override def put(x: Int): Unit = { buf += x }
}

trait Doubling extends IntQueue {
  abstract override def put(x: Int): Unit = { super.put(2*x) }
}

class MyQueue extends BasicIntQueue with Doubling {

}

trait Incrementing extends IntQueue {
  abstract override def put(x: Int) {
    println("Incrementing put called")
    super.put(x + 1)
  }
}

trait Filtering extends IntQueue {
  abstract override def put(x: Int) {
    println("Filtering put called")
    if (x >= 0) super.put(x)
  }
}

///////////////////////////////////////////////////
abstract class Employee
class CorporateEmployee extends Employee
class StoreEmployee extends Employee

trait DeliversFood extends StoreEmployee //表示只有继承自StoreEmployee的子类才能mix DeliversFood
class DeliveryPerson extends StoreEmployee with DeliversFood
//class Receptionist extends CorporateEmployee with DeliversFood //won't compile

//////////////////////////////////////////////////
trait StarFleeWarpCore {
  this: Starship => //这个表示trait只能被继承自Starship的子类所mix
}
class Starship
class Enterprise extends Starship with StarFleeWarpCore


/////////////////////////////////////////////////
trait WarpCore {
  //表示任何mix trait的类都必须有下面这个方法
  this: { def ejectWarpCore(password: String): Boolean } =>
}


object StackableTrait extends App{
  //val q = new BasicIntQueue
  val q = new MyQueue
  q.put(1)
  q.put(2)
  println(q.get())
  println(q.get())

  //Given these modifications, you can now pick and choose which
  // ones you want for a particular queue.For example, here is a queue that both
  // filters negative numbers and adds one to all numbers that it keeps

  //Once a trait is mixed into a class, you can alternatively call it a mixin
  /*
  The order of mixins is significant. (Once a trait is mixed into a class, you can
   alternatively call it a mixin.) Roughly speaking, traits further to the right
   take effect first. When you call a method on a class with mixins, the method
   in the trait furthest to the right is called first. If that method calls super,
   it invokes the method in the next trait to its left, and so on. In the previous
   example, Filtering's put is invoked first, so it removes integers that were negative
    to begin with. Incrementing's put is invoked second, so it adds one to those integers that remain
   */
  val queue = (new BasicIntQueue with Incrementing with Filtering)
  queue.put(-1);
  queue.put(0);
  queue.put(1)
  println(queue.get())
  println(queue.get())
}
